package cn.ssm.nft.turbo.base.utils;

import cn.ssm.nft.turbo.base.exception.RemoteCallException;
import com.alibaba.fastjson2.JSON;  // 使用FastJSON进行JSON序列化
import com.google.common.collect.ImmutableSet;  // Guava不可变集合
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;  // Spring断言工具
import org.springframework.util.StopWatch;  // 耗时监控工具

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;

import static cn.ssm.nft.turbo.base.exception.BizErrorCode.REMOTE_CALL_RESPONSE_IS_FAILED;
import static cn.ssm.nft.turbo.base.exception.BizErrorCode.REMOTE_CALL_RESPONSE_IS_NULL;

/**
 * 远程方法调用的包装工具类（核心功能：统一异常处理+响应校验+日志记录）
 */
public class RemoteCallWrapper {

    // 日志记录器
    private static Logger logger = LoggerFactory.getLogger(RemoteCallWrapper.class);

    // 成功状态校验方法白名单（通过反射调用）
    private static ImmutableSet<String> SUCCESS_CHECK_METHOD = ImmutableSet.of("isSuccess", "isSucceeded", "getSuccess");

    // 响应码获取方法白名单
    private static ImmutableSet<String> SUCCESS_CODE_METHOD = ImmutableSet.of("getResponseCode");

    // 可接受的成功响应码集合（"DUPLICATE"等表示幂等性成功）
    private static ImmutableSet<String> SUCCESS_CODE = ImmutableSet.of("SUCCESS", "DUPLICATE", "DUPLICATED_REQUEST");

    // 方法重载（核心方法）
    public static <T, R> R call(Function<T, R> function, T request, String requestName, boolean checkResponse,
                                boolean checkResponseCode) {
        StopWatch stopWatch = new StopWatch();  // 创建计时器
        R response = null;
        try {
            stopWatch.start();
            response = function.apply(request);  // 执行远程调用（核心Lambda表达式）
            stopWatch.stop();

            if (checkResponse) {  // 响应基础校验
                Assert.notNull(response, REMOTE_CALL_RESPONSE_IS_NULL.name());  // Spring非空断言
                if (!isResponseValid(response)) {  // 反射校验业务成功状态
                    logger.error("Response Invalid on Remote Call request {} , response {}",
                            JSON.toJSONString(request), JSON.toJSONString(response));
                    throw new RemoteCallException(JSON.toJSONString(response), REMOTE_CALL_RESPONSE_IS_FAILED);
                }
            }

            if (checkResponseCode) {  // 响应码校验模式
                Assert.notNull(response, REMOTE_CALL_RESPONSE_IS_NULL.name());
                if (!isResponseCodeValid(response)) {  // 反射校验响应码
                    logger.error("Response code Invalid on Remote Call request {} , response {}",
                            JSON.toJSONString(request), JSON.toJSONString(response));
                    throw new RemoteCallException(JSON.toJSONString(response), REMOTE_CALL_RESPONSE_IS_FAILED);
                }
            }

        } catch (IllegalAccessException | InvocationTargetException e) {  // 反射相关异常
            logger.error("Catch Exception on Remote Call :" + e.getMessage(), e);
            throw new IllegalArgumentException("Catch Exception on Remote Call " + e.getMessage(), e);
        } catch (Throwable e) {  // 兜底异常捕获
            logger.error("request exception {}", JSON.toJSONString(request));
            logger.error("Catch Exception on Remote Call :" + e.getMessage(), e);
            throw e;
        } finally {  // 最终日志记录
            if (logger.isInfoEnabled()) {
                logger.info("## Method={} ,## 耗时={}ms ,## [请求报文]:{},## [响应报文]:{}", requestName,
                        stopWatch.getTotalTimeMillis(),
                        JSON.toJSONString(request), JSON.toJSONString(response));
            }
        }
        return response;
    }

    // 反射校验业务状态（通过预定义方法名检测）
    private static <R> boolean isResponseValid(R response) throws IllegalAccessException, InvocationTargetException {
        Method successMethod = null;
        Method[] methods = response.getClass().getMethods();  // 获取所有public方法
        for (Method method : methods) {
            if (SUCCESS_CHECK_METHOD.contains(method.getName())) {  // 匹配白名单方法名
                successMethod = method;
                break;
            }
        }
        if (successMethod == null) return true;  // 未找到校验方法则默认成功
        return (Boolean) successMethod.invoke(response);  // 动态调用方法
    }

    // 反射校验响应码（通过getResponseCode方法获取状态码）
    private static <R> boolean isResponseCodeValid(R response) throws IllegalAccessException, InvocationTargetException {
        Method codeMethod = null;
        for (Method method : response.getClass().getMethods()) {
            if (SUCCESS_CODE_METHOD.contains(method.getName())) {
                codeMethod = method;
                break;
            }
        }
        if (codeMethod == null) return true;  // 无响应码方法则默认成功
        Object code = codeMethod.invoke(response);  // 获取响应码
        return SUCCESS_CODE.contains(String.valueOf(code));  // 判断是否在成功码集合中
    }
}